package scorer;

import java.util.ArrayList;
import java.util.Collections;

import tile.Tile;

public class Set {

	public enum TYPE {
		chow(3), pung(3), kong(4), eyes(2, false), other(-1, false);
		int size;
		boolean openAllowed;

		private TYPE(int n) {
			size = n;
			openAllowed = true;
		}

		private TYPE(int n, boolean oa) {
			this(n);
			openAllowed = oa;
		}
	}

	private boolean open;
	private ArrayList<Tile> tiles;
	private TYPE type;

	public Set(boolean isOpen, TYPE t) {
		open = isOpen;
		type = t;
		tiles = new ArrayList<Tile>();
	}

	public boolean isOpen() {
		return open;
	}

	public boolean isValid() {
		if (tiles.size() < 2)
			return false;
		Tile t0 = tiles.get(0), t1 = tiles.get(1), t2 = null, t3 = null;
		if (tiles.size() > 2)
			t2 = tiles.get(2);
		if (tiles.size() > 3)
			t3 = tiles.get(3);
		switch (type) {
			case chow:
				return t2 != null && !t0.suit.isHonors() && t0.suit == t1.suit
						&& t0.suit == t2.suit
						&& ((Integer) t0.value) + 1 == ((Integer) t1.value)
						&& ((Integer) t1.value) + 1 == ((Integer) t2.value);
			case kong:
				if (t3 == null || !t3.equals(t0))
					return false;
			case pung:
				if (t2 == null || !t2.equals(t0))
					return false;
			case eyes:
				return t1.equals(t0);
			case other:
				return tiles.size() == 14;
			default:
				return false;
		}
	}

	public boolean isValid(Tile t) {
		if (t == null)
			return false;
		if (tiles.isEmpty())
			return type == TYPE.chow ? !t.suit.isHonors() : true;
		if (type.size != -1 && tiles.size() == type.size)
			return false;
		if (type != TYPE.other) {
			for (Tile tile : tiles) {
				if (tile.suit != t.suit)
					return false;
			}
		} else {
			return tiles.size() < 14;
		}

		if (type == TYPE.chow) {
			int v0 = (Integer) tiles.get(0).value;
			int v = (Integer) t.value;
			if (tiles.size() == 1) {
				return v >= v0 - 2 && v <= v0 + 2 && v != v0;
			} else {
				Collections.sort(tiles);
				v0 = (Integer) tiles.get(0).value;
				int v1 = (Integer) tiles.get(1).value;
				return (v == v0 - 1) || (v == v1 + 1)
						|| (v == v0 + 1 && v == v1 - 1);
			}
		}

		return t.equals(tiles.get(0));
	}

	public boolean addTile(Tile t) {
		return isValid(t) && tiles.add(t);
	}

	public boolean removeTile(Tile t) {
		return tiles.remove(t);
	}

	public Tile getTile(int index) {
		if (index < 0 || index >= tiles.size())
			return null;
		return tiles.get(index);
	}

	public Tile removeTile(int index) {
		if (tiles.size() <= index)
			return null;
		return tiles.remove(index);
	}

	public ArrayList<String> getTiles() {
		ArrayList<String> t = new ArrayList<String>(tiles.size());
		for (Tile tile : tiles) {
			t.add(tile.toString());
		}
		return t;
	}

	public String getSet() {
		String set = "";
		if (type == TYPE.kong && !open)
			set += " c ";
		else if (open)
			set += " m ";
		else
			set += " h ";
		for (Tile t : tiles) {
			if (!t.isWinner) {
				set += t.toString();
			}
		}

		for (Tile t : tiles) {
			if (t.isWinner) {
				set += " " + t.toString();
			}
		}

		System.out.println(set);
		return set;
	}

	public boolean isOther() {
		return type == TYPE.other;
	}

	public String toString() {
		return (open ? "Open" : "Closed") + " " + type;
	}

}
